//============================================================================
// Name        : sin_path.cpp
// Author      : dfoelber
//============================================================================

// INCLUDES //
#include "physics/sin_path.h"
#include <math.h>
#include <iostream>
//////////////

using namespace std;

/**
* Constructor
* 
* @param originX The origin's X coordinate
* @param originY The origin's Y coordinate
* @param destX The destination's X coordinate
* @param destY The destination's Y coordinate
* @param apexX The apex's X coordinate
* @param apexY The apex's Y coordinate
* @param vel Velocity of the path
**/
SinPath::SinPath( int originX, int originY, int destX, int destY, int apexX, int apexY, double vel ) :
	Path(),
	velocity(vel),
	originX(originX),
	originY(originY),
	destX(destX),
	destY(destY),
	apexX(apexX),
	apexY(apexY)
{
}

/**
* Lets the path know that time has passed and to move accordingly.
* 
* Overridden from Path.
* 
* @param ms The time passed since last called
**/
void SinPath::TimePassed( int ms )
{
	Path::TimePassed(ms);
	
	if( IsMoving() && !IsPaused() )
	{
		double distance = ((double)ms / 40.0) * velocity;
		
		if( destX < originX )
			distance *= -1;
		
		double x = GetX(), y = GetY();
		CalculateCoordinates(GetX(), GetY(), distance, &x, &y);
		
		xDistance = x - GetX();
		yDistance = y - GetY();
		
		double moveX = 0.0, moveY = 0.0;
		x = y = 0.0;
		CalculateCoordinates(GetX(), GetY(), (destX - originX) / 20, &x, &y);
		moveX = x - GetX();
		moveY = y - GetY();
		
		if( moveX > 0 && moveY < 0 )
		{
			moveY *= -1;		
			double distance = sqrt( moveX * moveX + moveY * moveY );
			SetRotation( (int)((asin(moveY / distance) * (180 / M_PI))) );
		}
		else if( moveX > 0 && moveY > 0 )
		{	
			double distance = sqrt( moveX * moveX + moveY * moveY );
			SetRotation( 360 - (int)((asin(moveY / distance) * (180 / M_PI))) );		
		}
		else if( moveX < 0 && moveY > 0 )
		{	
			double distance = sqrt( moveX * moveX + moveY * moveY );
			SetRotation( 180 + (int)((asin(moveY / distance) * (180 / M_PI))) );		
		}
		else if( moveX < 0 && moveY < 0 )
		{	
			double distance = sqrt( moveX * moveX + moveY * moveY );
			SetRotation( 180 - (int)((asin(moveY / distance) * (180 / M_PI))) );		
		}
		else if( moveX < 0 && moveY == 0 )
		{	
			SetRotation(180);		
		}
		else
		{
			SetRotation(0);
		}
	}
}

/**
* Check if this path collided with another path.
* 
* Overridden from Path.
* 
* @param other The other path's area.
* @param xDistance The other path's X distance.
* @param yDistance The other path's Y distance. 
* 
* @return If collided
**/
bool SinPath::CheckCollision( Area* other, double otherX, double otherY )
{
	int side = area->Intersects(other, GetXDistance(), GetYDistance(), otherX, otherY );
	
	if( side != SIDE_NONE )
	{
		Path::CheckCollision( other, otherX, otherY );
		destX = GetX();
		destY = GetY();
		
		return true;
	}
	
	return false;
}

/**
* Gets if the path is still moving.
* 
* Overridden from Path.
* 
* @return If the path is moving
**/
bool SinPath::IsMoving()
{
	return (GetX() != destX) || (GetY() != destY);
}

void SinPath::CalculateCoordinates( double x, double y, double distance, double* newX, double* newY )
{
	if( destX > originX && x < destX && destX != originX )
	{
		if( x < apexX && x + distance >= apexX )
		{
			// for now
			*newX = apexX;
			*newY = apexY;
		}
		else if( x + distance >= destX )
		{
			*newX = destX;
			*newY = destY;
		}
		else
		{
			int usedY = x < apexX ? originY : destY;
			
			double percentHeight = 0;
			if( x < apexX )
			{
				percentHeight = sin(((double)(x + distance - originX) / (double)((apexX - originX) * 2)) * M_PI);
			}
			else
			{
				percentHeight = cos(((double)(x + distance - apexX) / (double)(destX - apexX)) * M_PI / 2);
			}
			
			double newHeight = usedY + ((double)(apexY - usedY) * percentHeight);
			
			*newY = newHeight;
			*newX = x + distance;
		}
	}
	else if( destX < originX && x > destX && destX != originX )
	{
		if( x > apexX && x + distance <= apexX )
		{
			// for now
			*newX = apexX;
			*newY = apexY;
		}
		else if( x + distance <= destX )
		{
			*newX = destX;
			*newY = destY;
		}
		else
		{
			int usedY = x > apexX ? originY : destY;
			
			double percentHeight = 0;
			if( x > apexX )
			{
				percentHeight = sin(((double)(x + distance - originX) / (double)((apexX - originX) * 2)) * M_PI);
			}
			else
			{
				percentHeight = cos(((double)(x + distance - apexX) / (double)(destX - apexX)) * M_PI / 2);
			}
			
			double newHeight = usedY + ((double)(apexY - usedY) * percentHeight);
			
			*newY = newHeight;
			*newX = x + distance;
		}
	}
}
